package lee.com.mqttlibrary.mqtt;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import androidx.annotation.Nullable;
import lee.com.mqttlibrary.callback.MyMQTTCallback;
import lee.com.mqttlibrary.util.MLog;

import static lee.com.mqttlibrary.model.Container.MQTT_CLIENT_ID;
import static lee.com.mqttlibrary.model.Container.MQTT_ISTOPIC;
import static lee.com.mqttlibrary.model.Container.MQTT_ISUNTOPIC;
import static lee.com.mqttlibrary.model.Container.MQTT_RECONNECT;
import static lee.com.mqttlibrary.model.Container.MQTT_TAG;
import static lee.com.mqttlibrary.model.Container.MQTT_TOPICS;

/**
 * CreateDate：18-9-15 on 上午10:33
 * Describe:
 * Coder: lee
 */
public class MQTTService extends Service {

    private MqttAndroidClient client;
    private MqttConnectOptions conOpt;
    private boolean isConnected, isReconnect;

    private Handler handler;
    private MyMQTTCallback myMQTTCallback;
    private String topics;
    private String clientId;

    private String host = "tcp://47.97.160.96:1883";
    private String userName = "mosquitto";
    private String passWord = "mosquitto";

    public MQTTService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        MLog.D("MqttService : onCreate");

        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

            }
        };
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MLog.D("MqttService : onStartCommand");
        if (null != intent) {
            String tag = intent.getStringExtra(MQTT_TAG);
            if (tag.equals(MQTT_ISTOPIC)) {//注册
                subTopics();
            } else if (tag.equals(MQTT_ISUNTOPIC)) {//反注册
                unSubTopics();
            } else if (tag.equals(MQTT_RECONNECT)) {//重连
                doClientConnection();
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        this.topics = intent.getStringExtra(MQTT_TOPICS);
        this.clientId = intent.getStringExtra(MQTT_CLIENT_ID);
        MLog.D("onBind ： topics = " + topics + "  clientId = " + clientId);
        init();
        return new MqttBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        MLog.D("onUnbind");
        stopSelf();
        return super.onUnbind(intent);
    }

    public class MqttBinder extends Binder {
        public MQTTService getService() {
            return MQTTService.this;
        }
    }

    @Override
    public void onDestroy() {
        MLog.D("MqttService ： onDestroy ");
        sendBack("destroy MqttService");
        try {
            myMQTTCallback = null;
            if (null != clientId) {
                client.unregisterResources();
            }
            if (client.isConnected()) {
                client.unsubscribe(topics);
            }
            if (null != clientId) {
                client.disconnect();
                client = null;
            }
        } catch (Exception e) {
            MLog.E("MqttService ： ERROR : " + e);
            e.printStackTrace();
        }
        super.onDestroy();
    }

    /**
     * 注册topic
     */
    private void subTopics() {
        MLog.D("MqttService ： subTopics isConnected = " + isConnected);
        if (isConnected) {
            MLog.D("go to subTopics " + topics);
            try {
                // 订阅Topic话题
                String watchId = topics;
                client.subscribe("send/app/" + watchId + "/#", 1, null, mqttSubListener);
            } catch (MqttException e) {
                MLog.E("subTopics ERROR : " + e);
            }
        }
    }

    /**
     * 反注册topic
     */
    private void unSubTopics() {
        MLog.D("MqttService ： subTopics isConnected = " + isConnected);
        if (isConnected) {
            MLog.D("go to subTopics ");
            try {
                // 订阅myTopic话题
                client.unsubscribe(topics);
            } catch (MqttException e) {
                MLog.E("subTopics ERROR : " + e);
            }
        }
    }

    private void init() {
        if (isConnected || null != client) {
            return;
        }
        MLog.D("MqttService : init");
        //每次注册服务的id不同
        MLog.D("MqttService : init ： host = " + host + " clientId = " + clientId);
        client = new MqttAndroidClient(this, host, clientId);
        // 设置MQTT监听并且接受消息
        client.setCallback(mqttMessageCallback);

        conOpt = new MqttConnectOptions();

        conOpt.setMaxInflight(100);
        // 清除缓存
        conOpt.setCleanSession(true);
        // 设置超时时间，单位：秒
        conOpt.setConnectionTimeout(10);
        // 心跳包发送间隔，单位：秒
        conOpt.setKeepAliveInterval(60);
        // 用户名
//        conOpt.setUserName(userName);
        // 密码
//        conOpt.setPassword(passWord);

//        conOpt.setWill(topics, MQTT_DEAD.getBytes(), 2, true);

        if (!isConnected) {
            doClientConnection();
        }

    }

    private void sendBack(String msg) {
//        Message message = handler.obtainMessage();
//        message.obj = msg;
//        handler.sendMessage(message);

        MLog.D("MqttService : msg ： " + msg);
    }

    /**
     * 连接MQTT服务器
     */
    private void doClientConnection() {
        sendBack("start to connect to MQTTService");
        if (null == client) return;
        if (!client.isConnected() && isConnectIsNomarl()) {
            try {
                MLog.D("MqttService : start to connect ......  ");
                MLog.D("MqttService : init ： host = " + host + " clientId = " + clientId);
                client.connect(conOpt, null, mqttConnectListener);
            } catch (MqttException e) {
                MLog.E("MqttService ： ERROR : " + e);
                e.printStackTrace();
            }
        }

    }


    /**
     * MQTT消息回调
     */
    private IMqttActionListener mqttPublishlListener = new IMqttActionListener() {

        @Override
        public void onSuccess(IMqttToken arg0) {
            MLog.D("消息发送成功 ");
            sendBack("mqtt publish success ");
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTResult(3, true);
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            arg1.printStackTrace();
            MLog.E("消息发送失败");
            sendBack("mqtt publish failed ");
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTResult(3, false);
        }
    };

    /**
     * MQTT是否注册成功
     */
    private IMqttActionListener mqttSubListener = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken iMqttToken) {
            MLog.D("注册成功 ");
            sendBack("subscribe Mqtt topic success");
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTResult(2, true);
        }

        @Override
        public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
            MLog.E("注册失败");
            sendBack("subscribe Mqtt topic failed");
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTResult(2, false);
        }
    };

    /**
     * MQTT是否连接成功
     */
    private IMqttActionListener mqttConnectListener = new IMqttActionListener() {

        @Override
        public void onSuccess(IMqttToken arg0) {
            MLog.D("连接成功 ");
            sendBack("connect to MQTTService success");
            isConnected = true;
            subTopics();
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTResult(1, isConnected);
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            arg1.printStackTrace();
            MLog.E("连接失败   -------");
            sendBack("connect to MQTTService failed and try reConnect");
            isConnected = false;
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTResult(1, isConnected);
            if (!isConnected) {
                if (null != handler) {
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            doClientConnection();
                        }
                    }, 60 * 1_000);
                }
            }
        }
    };


    /**
     * MQTT监听并且接受消息
     */
    private MqttCallback mqttMessageCallback = new MqttCallback() {

        @Override
        public void messageArrived(String topic, MqttMessage message) {

            MLog.D("收到MQTT消息");

            if (null != myMQTTCallback) {
                byte[] data = new byte[message.getPayload().length];
                System.arraycopy(message.getPayload(), 0, data, 0, data.length);
                myMQTTCallback.mqttData(topic, data);
            }
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {

        }

        @Override
        public void connectionLost(Throwable arg0) {
            MLog.E("失去连接   -------");
            sendBack("lost connect");
            isConnected = false;
            if (null != myMQTTCallback)
                myMQTTCallback.onMQTTError(-1, "connection lost !");
            isReconnect = true;
            if (!isConnected) {
                doClientConnection();
            }
        }
    };

    /**
     * 判断网络是否连接
     */
    private boolean isConnectIsNomarl() {
        MLog.D("MqttService ： isConnectIsNomarl : ");
        ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()) {
            String name = info.getTypeName();
            MLog.D("MQTT当前网络名称：" + name);
            sendBack("net type : " + name);
            return true;
        } else {
            MLog.E("MQTT 没有可用网络");
            sendBack("do not have Internet");
            if (null != handler) {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        doClientConnection();
                    }
                }, 60 * 1_000);
            }
            if (null != myMQTTCallback) {
                myMQTTCallback.onMQTTError(2, "Internet error ");
            }
            return false;
        }
    }

    public void sentMessage(String topic, byte[] msg) {
        if (null != client && client.isConnected()) {
            try {
                MqttMessage mqttMessage = new MqttMessage();
//                mqttMessage.setQos(1);
                mqttMessage.setPayload(msg);
                mqttMessage.setRetained(false);
                MLog.E("publish");
                client.publish(topic, mqttMessage, null, mqttPublishlListener);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    public void setMqttMessageCallback(MyMQTTCallback mqttMessageCallback) {
        this.myMQTTCallback = mqttMessageCallback;
    }
}
